/*
 * =====================================================================================
 *
 *       Filename:  interface.c
 *
 *    Description:  get interface infos
 *
 *        Version:  1.0
 *        Created:  2018年11月29日 00时22分00秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  YOUR NAME (), 
 *   Organization:  
 *
 * =====================================================================================
 */

/*
 * ioctl()获取网卡的所有信息
 */
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <net/if_arp.h>

/*
 * 如果缓冲区不够怎么办?
 *      只会取出部分的网卡信息
 */

int get_all_interfaces()
{
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(fd < 0) {
        perror("socket()");
        return -1;
    }
    struct ifconf _ifconf;
    struct ifreq  _ifreq[10];
    _ifconf.ifc_len = 10 * sizeof(struct ifreq);
    _ifconf.ifc_buf = (char *)_ifreq;

    if(ioctl(fd, SIOCGIFCONF, (char *)&_ifconf) < 0) {
        perror("ioctl(SIOCGIFCONF)");
        close(fd);
        return -1;
    }
    int i;
    int len = _ifconf.ifc_len/sizeof(struct ifreq);
    for(i = 0; i < len; i++) {
        printf("Interface: %s\n", _ifreq[i].ifr_name);

        if(ioctl(fd, SIOCGIFADDR, &_ifreq[i]) < 0) {
            perror("ioctl(SIOCGIFADDR)");
        }
        else {
            printf("\tIP: %s\n", inet_ntoa(((struct sockaddr_in *)(&_ifreq[i].ifr_addr))->sin_addr));
        }


        if(ioctl(fd, SIOCGIFDSTADDR, &_ifreq[i]) < 0) {
            perror("ioctl(SIOCGIFDSTADDR)");
        }
        else {
            printf("\tDSTIP: %s\n", inet_ntoa(((struct sockaddr_in *)(&_ifreq[i].ifr_dstaddr))->sin_addr));
        }

        if(ioctl(fd, SIOCGIFBRDADDR, &_ifreq[i]) < 0) {
            perror("ioctl(SIOCGIFBRDADDR)");
        }
        else {
            printf("\tBROADCAST: %s\n", inet_ntoa(((struct sockaddr_in *)(&_ifreq[i].ifr_broadaddr))->sin_addr));
        }

        if(ioctl(fd, SIOCGIFNETMASK, &_ifreq[i]) < 0) {
            perror("ioctl(SIOCGIFNETMASK)");
        }
        else {
            printf("\tNETMASK: %s\n", inet_ntoa(((struct sockaddr_in *)(&_ifreq[i].ifr_netmask))->sin_addr));
        }

        if(ioctl(fd, SIOCGIFMETRIC, &_ifreq[i]) < 0) {
            perror("ioctl(SIOCGIFMETRIC)");
        }
        else {
            printf("\tMETRIC: %d\n", _ifreq[i].ifr_metric);
        }

        if(ioctl(fd, SIOCGIFMTU, &_ifreq[i]) < 0) {
            perror("ioctl(SIOCGIFMTU)");
        }
        else {
            printf("\tMTU: %d\n", _ifreq[i].ifr_mtu);
        }

        if(ioctl(fd, SIOCGIFHWADDR, &_ifreq[i]) < 0) {
            perror("ioctl(SIOCGIFHWADDR)");
        }
        else {
            //MAC输出格式不正常，加上 & 0xff取出一个字节
            //不加 & 0xff为什么输出不正常呢?
            printf("\tMAC: %02X:%02X:%02X:%02X:%02X:%02X\n", 
                    _ifreq[i].ifr_hwaddr.sa_data[0] & 0xff,
                    _ifreq[i].ifr_hwaddr.sa_data[1] & 0xff,
                    _ifreq[i].ifr_hwaddr.sa_data[2] & 0xff,
                    _ifreq[i].ifr_hwaddr.sa_data[3] & 0xff,
                    _ifreq[i].ifr_hwaddr.sa_data[4] & 0xff,
                    _ifreq[i].ifr_hwaddr.sa_data[5] & 0xff);
            printf("\tMAC: %p:%p:%p:%p:%p:%p\n", 
                    &(_ifreq[i].ifr_hwaddr.sa_data[0]),
                    &(_ifreq[i].ifr_hwaddr.sa_data[1]),
                    &(_ifreq[i].ifr_hwaddr.sa_data[2]),
                    &(_ifreq[i].ifr_hwaddr.sa_data[3]),
                    &(_ifreq[i].ifr_hwaddr.sa_data[4]),
                    &(_ifreq[i].ifr_hwaddr.sa_data[5]));
        }

        if(ioctl(fd, SIOCGIFFLAGS, &_ifreq[i]) < 0) {
            perror("ioctl(SIOCGIFFLAGS)");
        }
        else {
            printf("\tFLAGS: %d\n", _ifreq[i].ifr_flags);
        }

        printf("\n");
    }
    return 0;
}

int main()
{
    return get_all_interfaces();
}



